/*
        绑定信息类的定义：
            1，交换机名称
            2，队列名称
            3，binding_key绑定规则
        绑定信息持久化功能的实现：
            1，创建/删除绑定信息表
            2，新增绑定信息数据
            3，删除绑定信息数据
            4，移除指定交换机的绑定信息——在删除交换机时会使用到
            5，移除指定队列的绑定信息——在删除队列时会使用到
            6，查询所有绑定信息数据——重启服务器时，用于历史数据的恢复
        绑定信息管理类
            1，创建绑定信息，并添加管理
            2，解除指定的绑定信息
            3，删除指定队列的绑定信息
            4，删除指定交换机的绑定信息
            4，获取交换机所有的绑定信息——收到消息后，决定分发给哪些队列
            5，判断指定信息是否存在
            6，获取当前绑定信息的数量
        7，销毁所有绑定信息
*/
#ifndef __M_BINDING_H__
#define __M_BINDING_H__
#include "../mqcommon/helpper.hpp"
#include "../mqcommon/logger.hpp"
#include "../mqcommon/mq_message.pb.h" //这里包含交换机类型，持久化等枚举类型
#include <iostream>
#include <string>
#include <memory>
#include <unordered_map>
#include <mutex>

namespace xgmq
{
    // 绑定信息类的定义
    struct Binding
    {
        using ptr = std::shared_ptr<Binding>;

        std::string exchange_name; // 交换机名称
        std::string msgQueue_name; // 队列名称
        std::string binding_key;   // 匹配规则
        Binding() {}
        Binding(const std::string &ename, const std::string &qname, const std::string &key)
            : exchange_name(ename), msgQueue_name(qname), binding_key(key)
        {
        }
    };
    // 交换机与队列之间的绑定关系是一对多的，一个交换机可能对应多个队列
    // 也就是说一个交换机可能包含多个绑定信息

    // 队列名称与绑定信息的映射
    using MsgQueueBindingMap = std::unordered_map<std::string, Binding::ptr>;
    // 交换机名称与上面结构的映射
    using BindingMap = std::unordered_map<std::string, MsgQueueBindingMap>;

    // 绑定信息持久化功能的实现
    class BindingMapper
    {
    public:
        BindingMapper(const std::string &dbfile)
            : _sql_help(dbfile)
        {
            // 针对传入的dbfile，判断是其路径是否存在
            FileHelper file_help(dbfile);
            std::string path = file_help.parentDirector(dbfile);
            if (file_help.isExits() == false)
            {
                file_help.createDirector(path);
            }
            // 创建/打开数据库
            assert(_sql_help.open());

            createTable();
        }
        void createTable()
        {
            // create table if not exists binding_table(
            // exchange_name varchar(32),msgQueue_name varchar(32),binding_key varchar(32));
            std::string sql = "create table if not exists binding_table(exchange_name varchar(32),msgQueue_name varchar(32),binding_key varchar(32));";
            assert(_sql_help.exec(sql, nullptr, nullptr));
        }
        void removeTable()
        {
            // drop table if exists binding_key;
            std::string sql = "drop table if exists binding_table;";
            _sql_help.exec(sql, nullptr, nullptr);
        }
        // 新增绑定信息
        bool insert(Binding::ptr &binding)
        {
            // insert into binding_table values(exchange_name,msgQueue_name,binding_key);
            std::stringstream ss;
            ss << "insert into binding_table values(";
            ss << "'" << binding->exchange_name << "',";
            ss << "'" << binding->msgQueue_name << "',";
            ss << "'" << binding->binding_key << "');";

            return _sql_help.exec(ss.str(), nullptr, nullptr);
        }
        // 删除绑定信息
        void remove(const std::string &ename, const std::string &qname)
        {
            // delete from binding_table where exchange_name=ename and msgQueue_name=qname;
            std::stringstream ss;
            ss << "delete from binding_table where exchange_name=";
            ss << "'" << ename << "'";
            ss << "and msgQueue_name=";
            ss << "'" << qname << "';";

            _sql_help.exec(ss.str(), nullptr, nullptr);
        }
        // 移除指定交换机的绑定信息（在删除交换机时会使用到）
        void removeExchangeBindings(const std::string &ename)
        {
            std::stringstream ss;
            ss << "delete from binding_table where exchange_name=";
            ss << "'" << ename << "';";

            _sql_help.exec(ss.str(), nullptr, nullptr);
        }
        // 移除指定队列的绑定信息
        void removeQueueBindings(const std::string &qname)
        {
            std::stringstream ss;
            ss << "delete from binding_table where msgQueue_name=";
            ss << "'" << qname << "';";

            _sql_help.exec(ss.str(), nullptr, nullptr);
        }
        // 查询所有绑定信息数据（在重启服务器，恢复内存数据时会使用到）
        BindingMap recovery()
        {
            BindingMap result;
            // select exchange_name,msgQueue_name,binding_key from binding_table;
            std::string sql = "select exchange_name,msgQueue_name,binding_key from binding_table;";
            _sql_help.exec(sql, selectCallback, &result);

            return result;
        }

    private:
        static int selectCallback(void *arg, int numrow, char **res, char **fields)
        {
            BindingMap *result = (BindingMap *)arg;
            Binding::ptr bp = std::make_shared<Binding>(res[0], res[1], res[2]);
            MsgQueueBindingMap &mqbp = (*result)[bp->exchange_name];
            mqbp.insert(std::make_pair(bp->msgQueue_name, bp));
            return 0;
        }

    private:
        SqliteHelper _sql_help;
    };

    // 绑定信息管理类
    class BindingManager
    {
    public:
        using ptr=std::shared_ptr<BindingManager>;
        BindingManager(const std::string &dbfile)
            : _mapper(dbfile)
        {
            _binding_map = _mapper.recovery();
        }
        bool bind(const std::string &ename, const std::string &qname, const std::string &key, bool durable=true)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _binding_map.find(ename);
            if (it != _binding_map.end() && it->second.find(qname) != it->second.end())
            {
                return true;
            }
            // 构建一个绑定关系对象
            Binding::ptr bp = std::make_shared<Binding>(ename, qname, key);
            // 是否需要进行持久化（数据库存储）
            if (durable == true)
            {
                _mapper.insert(bp);
            }
            auto &mqp = _binding_map[ename];
            mqp.insert(std::make_pair(qname, bp));

            return true;
        }

        void unbind(const std::string &ename, const std::string &qname)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto eit = _binding_map.find(ename);
            if (eit == _binding_map.end())
            {
                return;
            } // 没有交换机相关的绑定信息
            auto qit = eit->second.find(qname);
            if (qit == eit->second.end())
            {
                return;
            } // 没有队列相关的绑定信息
            _mapper.remove(ename, qname);
            _binding_map[ename].erase(qname);
        }
        // 移除交换机的相关绑定信息
        void removeExchangeBinding(const std::string &ename)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto eit = _binding_map.find(ename);
            if (eit == _binding_map.end())
            {
                return;
            } // 没有交换机相关的绑定信息

            _mapper.removeExchangeBindings(ename);
            _binding_map.erase(ename);
        }
        // 移除队列相关的绑定信息
        void removeQueueBinding(const std::string &qname)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            // 遍历所有交换机信息
            for (auto start = _binding_map.begin(); start != _binding_map.end(); ++start)
            {
                start->second.erase(qname);
            }
            _mapper.removeQueueBindings(qname);
        }
        // 获取绑定信息
        Binding::ptr getBinding(const std::string &ename, const std::string &qname)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto eit = _binding_map.find(ename);
            if (eit == _binding_map.end())
            {
                return Binding::ptr();
            }
            auto qit = eit->second.find(qname);
            if (qit == eit->second.end())
            {
                return Binding::ptr();
            }

            return qit->second;
        }
        // 获取交换机的绑定信息
        MsgQueueBindingMap getExchangeBinding(const std::string &ename)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto eit = _binding_map.find(ename);
            if (eit == _binding_map.end())
            {
                return MsgQueueBindingMap();
            }
            return eit->second;
        }
        bool isExists(const std::string &ename, const std::string &qname)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto eit = _binding_map.find(ename);
            if (eit == _binding_map.end())
            {
                return false;
            }
            auto qit = eit->second.find(qname);
            if (qit == eit->second.end())
            {
                return false;
            }
            return true;
        }
        size_t size()
        {
            size_t totalsize=0;
            for(auto start=_binding_map.begin();start!=_binding_map.end();++start)
            {
                totalsize+=start->second.size();
            }
            return totalsize;
        }
        void clear()
        {
            _mapper.removeTable();
            _binding_map.clear();
        }
    private:
        std::mutex _mutex;
        BindingMap _binding_map; // 存储所有的绑定信息
        BindingMapper _mapper;   // 实现信息的数据库存储
    };
}
#endif